use std::sync::Arc;

use actix_web::{post, web::ServiceConfig, HttpRequest, Scope};
use serde::{Deserialize, Serialize};

use crate::{
    error::new_err_static,
    store::user::{self, User},
    utils::{current_timestamp, pwd_encrypt},
    web::{
        req::Cbor,
        res::{new_body, CborResp},
        session::{save_session, Session},
    },
};

#[derive(Debug, Serialize)]
struct LoginRes {
    user: Arc<User>,
    token: String,
}

#[derive(Debug, Deserialize)]
struct LoginReq {
    account: String,
    pwd: String,
}

#[post("/login")]
pub async fn login(req: Cbor<LoginReq>, http_req: HttpRequest) -> CborResp<LoginRes> {
    let addr = http_req
        .peer_addr()
        .ok_or(new_err_static("invalid req"))?
        .to_string();
    let ret = user::get(&req.account, &req.pwd).await?;

    let user = Arc::new(ret);
    let token_raw = format!("{}-{}-{}", addr, user.account, current_timestamp());
    let token = pwd_encrypt(&token_raw);
    let res = LoginRes { user, token };
    save_session(res.token.clone(), res.user.clone());
    new_body(res)
}

#[derive(Debug, Deserialize)]
struct CreateReq {
    name: String,
    account: String,
    pwd: String,
}

#[derive(Debug, Serialize)]
struct CreateRes {
    id: i64,
}

#[post("/create")]
pub async fn create(_s: Session, req: Cbor<CreateReq>) -> CborResp<CreateRes> {
    let id = user::create(&req.name, &req.account, &req.pwd).await?;
    let res = CreateRes { id };
    new_body(res)
}


pub fn register(cfg: &mut ServiceConfig) {
    let scope = Scope::new("/user")
        .service(login)
        .service(create)
        ;
    cfg.service(scope);
}
